package lib.quasar.camera;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.VideoView;

import java.io.IOException;

import javax.xml.transform.ErrorListener;

import lib.quasar.camera.listener.OnCameraChangeListener;
import lib.quasar.camera.listener.OnCaptureChangeListener;
import lib.quasar.camera.state.CameraMachine;
import lib.quasar.camera.util.FileUtil;
import lib.quasar.util.LogUtil;

/**
 * description: 相机界面
 * created by kalu on 2018/4/27 20:16
 */
public class CameraView extends RelativeLayout implements CameraInterface.CameraOpenOverCallback, SurfaceHolder.Callback, CameraInf {

    //Camera状态机
    private final CameraMachine mCameraMachine = new CameraMachine(getContext().getApplicationContext(), this, this);

    //闪关灯状态
    private static final int TYPE_FLASH_AUTO = 0x021;
    private static final int TYPE_FLASH_ON = 0x022;
    private static final int TYPE_FLASH_OFF = 0x023;
    private int type_flash = TYPE_FLASH_OFF;

    //拍照浏览时候的类型
    public static final int TYPE_PICTURE = 0x001;
    public static final int TYPE_VIDEO = 0x002;
    public static final int TYPE_SHORT = 0x003;
    public static final int TYPE_DEFAULT = 0x004;

    //录制视频比特率
    public static final int MEDIA_QUALITY_HIGH = 20 * 100000;
    public static final int MEDIA_QUALITY_MIDDLE = 16 * 100000;
    public static final int MEDIA_QUALITY_LOW = 12 * 100000;
    public static final int MEDIA_QUALITY_POOR = 8 * 100000;
    public static final int MEDIA_QUALITY_FUNNY = 4 * 100000;
    public static final int MEDIA_QUALITY_DESPAIR = 2 * 100000;
    public static final int MEDIA_QUALITY_SORRY = 1 * 80000;

    public static final int BUTTON_STATE_ONLY_CAPTURE = 0x101;      //只能拍照
    public static final int BUTTON_STATE_ONLY_RECORDER = 0x102;     //只能录像
    public static final int BUTTON_STATE_BOTH = 0x103;              //两者都可以

    // 照片保存时的预览
    private ImageView mPhoto;
    private ImageView mSwitchCamera;
    private ImageView mFlashLamp;
    private FoucsView mFoucsView;
    private MediaPlayer mMediaPlayer;
    private VideoView mVideoView;

    private float screenProp = 0f;

    private Bitmap captureBitmap;   //捕获的图片
    private Bitmap firstFrame;      //第一帧图片
    private String videoUrl;        //视频URL

    //缩放梯度
    private float zoomGradient = 0;

    private boolean firstTouch = true;
    private float firstTouchLength = 0;

    public CameraView(Context context) {
        this(context, null);
    }

    public CameraView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //get AttributeSet
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CameraView, defStyleAttr, 0);
        a.recycle();

        //缩放梯度
        zoomGradient = getWidth() / 16f;
        LogUtil.e("", "zoom = " + zoomGradient);

        // 添加10个孩子
        setWillNotDraw(false);
        // 1.预览画面
        mVideoView = new VideoView(context);
        RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
        mVideoView.setLayoutParams(params2);
        addView(mVideoView);

        // 点击对焦
        mPhoto = new ImageView(context);
        RelativeLayout.LayoutParams params3 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
        mPhoto.setLayoutParams(params3);
        mPhoto.setBackgroundColor(Color.parseColor("#00000000"));
        mPhoto.setVisibility(View.INVISIBLE);
        addView(mPhoto);

        // 摄像头切换
        mSwitchCamera = new ImageView(context);
        RelativeLayout.LayoutParams params4 = new RelativeLayout.LayoutParams(100, 100);
        params4.setMargins(50, 50, 50, 50);
        params4.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        params4.addRule(RelativeLayout.ALIGN_PARENT_TOP);
        mSwitchCamera.setLayoutParams(params4);
        addView(mSwitchCamera);

        // 闪光灯
        mFlashLamp = new ImageView(context);
        RelativeLayout.LayoutParams params5 = new RelativeLayout.LayoutParams(100, 100);
        params5.setMargins(50, 50, 200, 50);
        params5.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        params4.addRule(RelativeLayout.ALIGN_PARENT_TOP);
        mFlashLamp.setLayoutParams(params5);
        setFlashRes();
        addView(mFlashLamp);
        mFlashLamp.setOnClickListener(v -> {
            type_flash++;
            if (type_flash > 0x023)
                type_flash = TYPE_FLASH_AUTO;
            setFlashRes();
        });

        // 对焦
        mFoucsView = new FoucsView(context);
        RelativeLayout.LayoutParams params7 = new RelativeLayout.LayoutParams(200, 200);
        mFoucsView.setLayoutParams(params7);
        mFoucsView.setVisibility(View.INVISIBLE);
        addView(mFoucsView);

        mVideoView.getHolder().addCallback(this);
        //切换摄像头
        mSwitchCamera.setOnClickListener(v -> mCameraMachine.swtich(mVideoView.getHolder(), screenProp));

        // 拍照按钮
        btn_capture = new CaptureButton(getContext(), 200);
        RelativeLayout.LayoutParams params8 = new RelativeLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        params8.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        params8.addRule(RelativeLayout.CENTER_HORIZONTAL);
        params8.setMargins(0, 0, 0, 100);
        btn_capture.setLayoutParams(params8);
        addView(btn_capture);

        //取消按钮
        btn_cancel = new TypeButton(getContext(), TypeButton.TYPE_CANCEL, 200);
        RelativeLayout.LayoutParams params9 = new RelativeLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        params9.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        params9.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
        params9.setMargins(200, 0, 0, 100);
        btn_cancel.setLayoutParams(params9);
        addView(btn_cancel);

        //确认按钮
        btn_confirm = new TypeButton(getContext(), TypeButton.TYPE_CONFIRM, 200);
        RelativeLayout.LayoutParams params10 = new RelativeLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
        params10.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        params10.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        params10.setMargins(0, 0, 200, 100);
        btn_confirm.setLayoutParams(params10);
        addView(btn_confirm);

        // 对焦提示信息
        txt_tip = new TextView(getContext());
        RelativeLayout.LayoutParams params11 = new RelativeLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, 50);
        params11.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        params11.addRule(RelativeLayout.CENTER_HORIZONTAL);
        params11.setMargins(0, 0, 0, 400);
        txt_tip.setLayoutParams(params11);
        txt_tip.setText("轻触拍照，长按摄像");
        txt_tip.setTextColor(0xFFFFFFFF);
        txt_tip.setGravity(Gravity.CENTER);
        addView(txt_tip);

        btn_capture.setOnCaptureChangeListener(new OnCaptureChangeListener() {
            @Override
            public void takePictures() {
                mSwitchCamera.setVisibility(INVISIBLE);
                mFlashLamp.setVisibility(INVISIBLE);
                mCameraMachine.capture();
            }

            @Override
            public void recordShort(final long time) {
                setTextWithAnimation("录制时间过短");
                mSwitchCamera.setVisibility(VISIBLE);
                mFlashLamp.setVisibility(VISIBLE);
                postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        mCameraMachine.stopRecord(true, time);
                    }
                }, 1500 - time);
                startAlphaAnimation();
            }

            @Override
            public void recordStart() {
                mSwitchCamera.setVisibility(INVISIBLE);
                mFlashLamp.setVisibility(INVISIBLE);

                final VideoView child1 = (VideoView) getChildAt(0);
                mCameraMachine.record(child1.getHolder().getSurface(), screenProp);
                startAlphaAnimation();
            }

            @Override
            public void recordEnd(long time) {
                mCameraMachine.stopRecord(false, time);
                startAlphaAnimation();
                startTypeBtnAnimator();
            }

            @Override
            public void recordZoom(float zoom) {
                LogUtil.e("", "recordZoom");
                mCameraMachine.zoom(zoom, CameraInterface.TYPE_RECORDER);
            }

            @Override
            public void recordError() {
            }
        });


        btn_cancel.setOnClickListener(view -> {
            final VideoView child1 = (VideoView) getChildAt(0);
            mCameraMachine.cancle(child1.getHolder(), screenProp);
            startAlphaAnimation();
//                resetCaptureLayout();
        });

        btn_confirm.setOnClickListener(view -> {

            if (mOnCameraChangeListener != null) {
                mOnCameraChangeListener.onPhotoSucc(captureBitmap);
            }

            mCameraMachine.confirm();
            startAlphaAnimation();
//                resetCaptureLayout();
        });


        //默认Typebutton为隐藏
        btn_cancel.setVisibility(GONE);
        btn_confirm.setVisibility(GONE);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        float widthSize = mVideoView.getMeasuredWidth();
        float heightSize = mVideoView.getMeasuredHeight();
        if (screenProp == 0) {
            screenProp = heightSize / widthSize;
        }
    }

    /************************************************************************/

    private CaptureButton btn_capture;      //拍照按钮
    private TypeButton btn_confirm;         //确认按钮
    private TypeButton btn_cancel;          //取消按钮
    private TextView txt_tip;               //提示文本

    public void startTypeBtnAnimator() {
        //拍照录制结果后的动画
        btn_capture.setVisibility(GONE);
        btn_cancel.setVisibility(VISIBLE);
        btn_confirm.setVisibility(VISIBLE);
        btn_cancel.setClickable(false);
        btn_confirm.setClickable(false);
        ObjectAnimator animator_cancel = ObjectAnimator.ofFloat(btn_cancel, "translationX", getWidth() / 4, 0);
        ObjectAnimator animator_confirm = ObjectAnimator.ofFloat(btn_confirm, "translationX", -getWidth() / 4, 0);

        AnimatorSet set = new AnimatorSet();
        set.playTogether(animator_cancel, animator_confirm);
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                super.onAnimationEnd(animation);
                btn_cancel.setClickable(true);
                btn_confirm.setClickable(true);
            }
        });
        set.setDuration(200);
        set.start();
    }

    public void resetCaptureLayout() {
        btn_capture.resetState();
        btn_cancel.setVisibility(GONE);
        btn_confirm.setVisibility(GONE);
        btn_capture.setVisibility(VISIBLE);
    }


    public void startAlphaAnimation() {
        ObjectAnimator animator_txt_tip = ObjectAnimator.ofFloat(txt_tip, "alpha", 1f, 0f);
        animator_txt_tip.setDuration(500);
        animator_txt_tip.start();
    }

    public void setTextWithAnimation(String tip) {
        txt_tip.setText(tip);
        ObjectAnimator animator_txt_tip = ObjectAnimator.ofFloat(txt_tip, "alpha", 0f, 1f, 1f, 0f);
        animator_txt_tip.setDuration(2500);
        animator_txt_tip.start();
    }

    public void setDuration(int duration) {
        btn_capture.setDuration(duration);
    }

    public void setButtonFeatures(int state) {
        btn_capture.setButtonFeatures(state);
    }

    public void showTip() {
        txt_tip.setVisibility(VISIBLE);
    }

    /************************************************************************/

    @Override
    public void cameraHasOpened() {

        final VideoView child1 = (VideoView) getChildAt(0);
        CameraInterface.getInstance().doStartPreview(child1.getHolder(), screenProp);
    }

    //生命周期onResume
    public void onResume() {
        LogUtil.e("", "JCameraInf onResume");
        resetState(TYPE_DEFAULT); //重置状态
        CameraInterface.getInstance().registerSensorManager(getContext().getApplicationContext());
        CameraInterface.getInstance().setSwitchView(mSwitchCamera, mFlashLamp);
        final VideoView child1 = (VideoView) getChildAt(0);
        mCameraMachine.start(child1.getHolder(), screenProp);
    }

    //生命周期onPause
    public void onPause() {
        LogUtil.e("", "JCameraInf onPause");
        stopVideo();
        resetState(TYPE_PICTURE);
        CameraInterface.getInstance().isPreview(false);
        CameraInterface.getInstance().unregisterSensorManager(getContext().getApplicationContext());
    }

    //SurfaceView生命周期
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        new Thread() {
            @Override
            public void run() {
                CameraInterface.getInstance().doOpenCamera(CameraView.this);
            }
        }.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        LogUtil.e("", "JCameraInf SurfaceDestroyed");
        CameraInterface.getInstance().doDestroyCamera();
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (event.getPointerCount() == 1) {
                    //显示对焦指示器
                    setFocusViewWidthAnimation(event.getX(), event.getY());
                }
                if (event.getPointerCount() == 2) {
                    Log.i("CJT", "ACTION_DOWN = " + 2);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (event.getPointerCount() == 1) {
                    firstTouch = true;
                }
                if (event.getPointerCount() == 2) {
                    //第一个点
                    float point_1_X = event.getX(0);
                    float point_1_Y = event.getY(0);
                    //第二个点
                    float point_2_X = event.getX(1);
                    float point_2_Y = event.getY(1);

                    float result = (float) Math.sqrt(Math.pow(point_1_X - point_2_X, 2) + Math.pow(point_1_Y -
                            point_2_Y, 2));

                    if (firstTouch) {
                        firstTouchLength = result;
                        firstTouch = false;
                    }
                    if ((int) (result - firstTouchLength) / zoomGradient != 0) {
                        firstTouch = true;
                        mCameraMachine.zoom(result - firstTouchLength, CameraInterface.TYPE_CAPTURE);
                    }
//                    Log.i("CJT", "result = " + (result - firstTouchLength));
                }
                break;
            case MotionEvent.ACTION_UP:
                firstTouch = true;
                break;
        }
        return true;
    }

    //对焦框指示器动画
    private void setFocusViewWidthAnimation(float x, float y) {
        mCameraMachine.foucs(x, y, new CameraInterface.FocusCallback() {
            @Override
            public void focusSuccess() {
                mFoucsView.setVisibility(INVISIBLE);
            }
        });
    }

    /**************************************************
     * 对外提供的API                     *
     **************************************************/

    public void setSaveVideoPath(String path) {
        CameraInterface.getInstance().setSaveVideoPath(path);
    }

    //设置CaptureButton功能（拍照和录像）
    public void setFeatures(int state) {
        setButtonFeatures(state);
    }

    //设置录制质量
    public void setMediaQuality(int quality) {
        CameraInterface.getInstance().setMediaQuality(quality);
    }

    @Override
    public void resetState(int type) {
        switch (type) {
            case TYPE_VIDEO:
                stopVideo();    //停止播放
                //初始化VideoView
                FileUtil.deleteFile(videoUrl);
                mVideoView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                mCameraMachine.start(mVideoView.getHolder(), screenProp);
                break;
            case TYPE_PICTURE:
                mPhoto.setVisibility(INVISIBLE);
                break;
            case TYPE_SHORT:
                break;
            case TYPE_DEFAULT:
                mVideoView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                break;
        }
        mSwitchCamera.setVisibility(VISIBLE);
        mFlashLamp.setVisibility(VISIBLE);
        resetCaptureLayout();
    }

    @Override
    public void confirmState(int type) {
        switch (type) {
            case TYPE_VIDEO:
                stopVideo();    //停止播放
                mVideoView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
                mCameraMachine.start(mVideoView.getHolder(), screenProp);
                if (mOnCameraChangeListener != null) {
                    mOnCameraChangeListener.onRecordSucc(videoUrl, firstFrame);
                }
                break;
            case TYPE_PICTURE:
                mPhoto.setVisibility(INVISIBLE);
                if (mOnCameraChangeListener != null) {
                    mOnCameraChangeListener.onPhotoSucc(captureBitmap);
                }
                break;
            case TYPE_SHORT:
                break;
            case TYPE_DEFAULT:
                break;
        }
        resetCaptureLayout();
    }

    @Override
    public void showPicture(Bitmap bitmap, boolean isVertical) {
        if (isVertical) {
            mPhoto.setScaleType(ImageView.ScaleType.FIT_XY);
        } else {
            mPhoto.setScaleType(ImageView.ScaleType.FIT_CENTER);
        }
        captureBitmap = bitmap;
        mPhoto.setImageBitmap(bitmap);
        mPhoto.setVisibility(VISIBLE);
        startAlphaAnimation();
        startTypeBtnAnimator();
    }

    @Override
    public void playVideo(Bitmap firstFrame, final String url) {
        videoUrl = url;
        CameraView.this.firstFrame = firstFrame;
        new Thread(new Runnable() {
            @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
            @Override
            public void run() {
                try {
                    if (mMediaPlayer == null) {
                        mMediaPlayer = new MediaPlayer();
                    } else {
                        mMediaPlayer.reset();
                    }
                    mMediaPlayer.setDataSource(url);
                    mMediaPlayer.setSurface(mVideoView.getHolder().getSurface());
                    mMediaPlayer.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT);
                    mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
                    mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer
                            .OnVideoSizeChangedListener() {
                        @Override
                        public void
                        onVideoSizeChanged(MediaPlayer mp, int width, int height) {

                            int videoWidth = mMediaPlayer.getVideoWidth();
                            int videoHeight = mMediaPlayer.getVideoHeight();
                            if (videoWidth <= videoHeight) return;

                            RelativeLayout.LayoutParams params = (LayoutParams) mVideoView.getLayoutParams();
                            int size = ((videoHeight / videoWidth) * getWidth());
                            params.width = LayoutParams.MATCH_PARENT;
                            params.height = size;
                            params.addRule(RelativeLayout.CENTER_IN_PARENT);
                            mVideoView.setLayoutParams(params);
                        }
                    });
                    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mMediaPlayer.start();
                        }
                    });
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.prepare();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    @Override
    public void stopVideo() {
        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
            mMediaPlayer.stop();
            mMediaPlayer.release();
            mMediaPlayer = null;
        }
    }

    @Override
    public void setTip(String tip) {
        txt_tip.setText(tip);
    }

    @Override
    public void startPreviewCallback() {
        LogUtil.e("", "startPreviewCallback");
        handlerFoucs(mFoucsView.getWidth() / 2, mFoucsView.getHeight() / 2);
    }

    @Override
    public boolean handlerFoucs(float x, float y) {

        // TODO: 2018/4/27
//        if (y > mCaptureLayout.getTop()) {
//            return false;
//        }
        mFoucsView.setVisibility(VISIBLE);
        if (x < mFoucsView.getWidth() / 2) {
            x = mFoucsView.getWidth() / 2;
        }
        if (x > getWidth() - mFoucsView.getWidth() / 2) {
            x = getWidth() - mFoucsView.getWidth() / 2;
        }
        if (y < mFoucsView.getWidth() / 2) {
            y = mFoucsView.getWidth() / 2;
        }

        // TODO: 2018/4/27
//        if (y > mCaptureLayout.getTop() - mFoucsView.getWidth() / 2) {
//            y = mCaptureLayout.getTop() - mFoucsView.getWidth() / 2;
//        }
        mFoucsView.setX(x - mFoucsView.getWidth() / 2);
        mFoucsView.setY(y - mFoucsView.getHeight() / 2);
        ObjectAnimator scaleX = ObjectAnimator.ofFloat(mFoucsView, "scaleX", 1, 0.6f);
        ObjectAnimator scaleY = ObjectAnimator.ofFloat(mFoucsView, "scaleY", 1, 0.6f);
        ObjectAnimator alpha = ObjectAnimator.ofFloat(mFoucsView, "alpha", 1f, 0.4f, 1f, 0.4f, 1f, 0.4f, 1f);
        AnimatorSet animSet = new AnimatorSet();
        animSet.play(scaleX).with(scaleY).before(alpha);
        animSet.setDuration(400);
        animSet.start();
        return true;
    }

    private void setFlashRes() {
        switch (type_flash) {
            case TYPE_FLASH_AUTO:
                mFlashLamp.setImageResource(R.drawable.ic_flash_auto);
                mCameraMachine.flash(Camera.Parameters.FLASH_MODE_AUTO);
                break;
            case TYPE_FLASH_ON:
                mFlashLamp.setImageResource(R.drawable.ic_flash_on);
                mCameraMachine.flash(Camera.Parameters.FLASH_MODE_ON);
                break;
            case TYPE_FLASH_OFF:
                mFlashLamp.setImageResource(R.drawable.ic_flash_off);
                mCameraMachine.flash(Camera.Parameters.FLASH_MODE_OFF);
                break;
        }
    }

    /**********************************************/

    private OnCameraChangeListener mOnCameraChangeListener;

    public void setOnCameraChangeListener(OnCameraChangeListener mOnCameraChangeListener) {
        this.mOnCameraChangeListener = mOnCameraChangeListener;
    }
}
